package com.wans.guli.cart.interceptor;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wans.guli.cart.vo.MemberVO;
import com.wans.guli.cart.vo.UserInfoTo;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.UUID;

@Component
public class CartUserKeyCheckInterceptor implements HandlerInterceptor {

    public static final ThreadLocal<UserInfoTo> threadLocal = new ThreadLocal<>();

    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 方法执行之后，返回modelAndView之前
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  handler  that started asynchronous
     *                 execution, for type and/or instance examination
     * @param ex       exception thrown on handler execution, if any
     * @throws Exception in case of errors
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

    /**
     * 方法执行之后，返回modelAndView之前
     *
     * @param request      current HTTP request
     * @param response     current HTTP response
     * @param handler      handler  that started asynchronous
     *                     execution, for type and/or instance examination
     * @param modelAndView the {@code ModelAndView} that the handler returned
     *                     (can also be {@code null})
     * @throws Exception in case of errors
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 给未登录的用户设置一个 游客cookie
        UserInfoTo userInfoTo = threadLocal.get();
        if (ObjectUtil.isEmpty(userInfoTo)) return; // 未知原因 - 线程中读取不到用户信息

        if (StrUtil.isBlank(userInfoTo.getUserKey())) {

            if (userInfoTo.getTempUser()) {
                // 临时 用户 的 请求

                // 设置一个游客cookie
                String userKeyValue = UUID.randomUUID().toString().replace("-", "");
                Cookie userKeyCookie = new Cookie("user-key", userKeyValue);
                userKeyCookie.setDomain("gulimall.com");
                userKeyCookie.setMaxAge(60 * 60 * 24 * 30);
                response.addCookie(userKeyCookie);
            } else {
                // 登录 用户 的 请求

                // 设置一个 user-key cookie
                String userKeyValue = UUID.randomUUID().toString().replace("-", "");
                Cookie userKeyCookie = new Cookie("user-key", userKeyValue);
                userKeyCookie.setDomain("gulimall.com");
                userKeyCookie.setMaxAge(60 * 60 * 24 * 30);
                // response.addCookie(userKeyCookie); 登录用户不再设置 cookie
            }

        }

        // 移除 user-key cookie 已登陆
        if (userInfoTo.getRemoveTempUser()) {
            String userKeyValue = UUID.randomUUID().toString().replace("-", "");
            Cookie userKeyCookie = new Cookie("user-key", userKeyValue);
            userKeyCookie.setDomain("gulimall.com");
            // 关键设置 过期为 0
            userKeyCookie.setMaxAge(0);
            response.addCookie(userKeyCookie);
        }

        // 清除线程变量
        threadLocal.remove();

    }

    /**
     * 方法执行之前
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  chosen handler to execute, for type and/or instance evaluation
     * @return {@code true} if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     * @throws Exception in case of errors
     */
    @Override
    @SneakyThrows
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        UserInfoTo userInfo = new UserInfoTo();

        // 获取用户信息 - session - redis
        String loginMember = (String) request.getSession().getAttribute("loginMember");
        if (loginMember != null) {
            // 这次请求用户是登录的
            MemberVO memberVO = objectMapper.readValue(loginMember, MemberVO.class);
            userInfo.setUserId(memberVO.getId());
            userInfo.setTempUser(false);
        } else {
            userInfo.setTempUser(true);
        }

        // 获取用户信息 - cookie - 获取id信息
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            Cookie userKeyCookie = Arrays.stream(cookies)
                    .filter(cookie -> "user-key".equals(cookie.getName()))
                    .findFirst().orElse(null);

            if (userKeyCookie != null) {
                // 获取用户信息 - cookie - 获取userKey信息
                String userKey = userKeyCookie.getValue();
                userInfo.setUserKey(userKey);
            }
        }


        // 放入线程变量
        threadLocal.set(userInfo);

        return true;
    }
}
